zip' _ [] = []
zip' [] _ = []
zip' (a:ax) (b:bx) = (a,b) : (zip' ax bx)

zipWith' f _ [] = []
zipWith' f [] _ = []
zipWith' f (a:ax) (b:bx) = (f a b) : (zipWith' f ax bx)

head' (a:ax) = a

last' [a] = a
last' (a:ax) = last' ax

tail' [] = []
tail' (a:ax) = ax

map' :: (Int -> Int) -> [Int] -> [Int]
map' f [] = []
map' f (a:ax) = (f a) : (map' f ax)

foldl' :: (Int -> Int -> Int) -> Int -> [Int] -> Int
foldl' f r [] = r
foldl' f r (a:ax) = foldl' f (f r a) ax

filter' p [] = []
filter' p (a:ax) = if p a then a : (filter' p ax) else filter' p ax

app [] bx = bx
app (a:ax) bx = a : (app ax bx)

reverse' [] = []
reverse' (a:ax) = app (reverse ax) [a]

drop' _ [] = []
drop' 0 ax = ax
drop' n (a:ax) = drop' (n-1) ax

product' [] = 1
product' (a:ax) = a * (product' ax)

take' _ [] = []
take' 0 _ = []
take' n (a:ax) = a : (take' (n-1) ax)

scanl' f r [] = [r]
scanl' f r (a:ax) = r : (scanl' f (f r a) ax)

sigma' n = foldl (+) 0 [1..n]

range' x y = if x == y then [x] else x : (range' (x+1) y)

gcd' a b
  | b == 0 = a
  | otherwise = gcd' b (mod a b) 

removeAt' [] _ = []
removeAt' (a:ax) 0 = removeAt' ax (-1)
removeAt' (a:ax) i = a : (removeAt' ax (i-1))

pal xs = xs == (reverse' xs)

rotate l 0 = l
rotate (x:xs) n = rotate (app xs [x]) (n-1)


insertAt ch str 0 = ch : str
insertAt ch (a:ax) n = a : (insertAt ch ax (n-1))

slice xs i l = take l (drop i xs)
